package Records.MusicPlayer;

/**
 *
 * @author Alexander
 */
import Records.Main.RecordsMain;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;
import net.sourceforge.jaad.spi.javasound.AACAudioFileReader;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;

public class MusicPlayer extends Thread {

    SourceDataLine playbackLine;
    private static String filename, sources;
    private boolean getTime = false;
    private static String EndDur, MostCurrentLocation, trackViewUrl,
            Dur, Time, URL_Song = "", URL_Artist = "";
    private static int DurationTimer;
    private static float elapsed, percent;
    private static long startTime = 0, stopTime = 0, PauseTime, ResumeTime, TimeWaste;

    public MusicPlayer(String CurrentSongPath, String Location) {
        DurationTimer = 0;
        filename = CurrentSongPath;
        sources = Location;
        getDuration();
    }

    public void close() {
        System.out.println("MusicPlayer.close()");

        if (playbackLine != null) {
            playbackLine.stop();
            playbackLine.drain();
            playbackLine.close();
            playbackLine = null;
        }
        getTime = false;
        RecordsMain.getUI().PlayTime.setText("0:00 of 0:00");
        RecordsMain.getUI().ProgBar.setValue(0);
        //RecordsMain.getUI().setCurrentPath("");
    }

    public void run() {
        System.out.println("MusicPlayer.run()");
        try {
            getTime = true;
            AudioInputStream AIS = null;
            AudioFormat myFormat = null;
            File soundFile = new File(filename);

            AIS = getAIS(soundFile);
            myFormat = AIS.getFormat();

            DataLine.Info info = new DataLine.Info(SourceDataLine.class, myFormat, AudioSystem.NOT_SPECIFIED);

            if (!AudioSystem.isLineSupported(info)) {
                AudioFormat decodedFormat = new AudioFormat(
                        AudioFormat.Encoding.PCM_SIGNED,
                        myFormat.getSampleRate(),
                        16, // sample size in bits
                        myFormat.getChannels(),
                        myFormat.getChannels() * 2,
                        myFormat.getSampleRate(),
                        false);
                AIS = AudioSystem.getAudioInputStream(decodedFormat, AIS);
                myFormat = AIS.getFormat();
            }
            playbackLine = AudioSystem.getSourceDataLine(myFormat);
            playbackLine.open(myFormat);
            int frameSizeInBytes = myFormat.getFrameSize();
            int bufferLengthInFrames = playbackLine.getBufferSize() / 8;
            int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
            byte[] data = new byte[bufferLengthInBytes];
            playbackLine.start();

            PlayerUserInterface.setStatus("PLAYING");
            int nBytesRead;
            try {
                while ((nBytesRead = AIS.read(data)) != -1) {
                    int numBytesRemaining = nBytesRead;
                    getPlayTime();
                    while (numBytesRemaining > 0) {
                        numBytesRemaining -= playbackLine.write(data, 0, numBytesRemaining);
                    }

                }
            } catch (IOException ex) {
                Logger.getLogger(MusicPlayer.class.getName()).log(Level.SEVERE, null, ex);
            }
            close();
        } catch (LineUnavailableException ex) {
            Logger.getLogger(MusicPlayer.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public void pausePlayback() {
        System.out.println("MusicPlayer.pausePlayback()");
        if (playbackLine != null) {
            if ("PLAYING".equals(PlayerUserInterface.getStatus())) {
                playbackLine.stop();
            }
            setPauseTime(System.currentTimeMillis()); //time at Pause
            //UserInterfaceUI.PlayTime.setText(Time)
        }
    }

    public void resumePlayback() {
        System.out.println("MusicPlayer.resumePlayback()");
        if (playbackLine != null) {
            if ("PAUSED".equals(PlayerUserInterface.getStatus())) {
                setResumeTime((System.currentTimeMillis() - PauseTime) / 1000); //Time at Resume
                setTimeWaste(TimeWaste + ResumeTime);
                playbackLine.start();
            }
        }
    }

    public void getPlayTime() {
        System.out.println("MusicPlayer.getPlayTime()");

        if (getTime = true) {
            setElapsed((System.currentTimeMillis() - startTime) / 1000);
            setElapsed(getElapsed() - TimeWaste);
            percent = (getElapsed() * 100) / DurationTimer;
            int Min = (int) getElapsed() / 60;
            int Sec = (int) getElapsed() % 60;
            String Secs;

            if (Sec < 10) {
                Secs = "0" + Sec;
            } else {
                Secs = "" + Sec;
            }
            Dur = Min + ":" + Secs;
            Time = Dur + " of " + EndDur;
            RecordsMain.getUI().PlayTime.setText(Time);
            RecordsMain.getUI().ProgBar.setMinorTickSpacing(1);
            RecordsMain.getUI().ProgBar.setValue((int) percent);
        }
    }

    public AudioInputStream getAIS(File soundFile) {
        System.out.println("MusicPlayer.getAIS(" + soundFile.getAbsolutePath() + ")");

        AudioInputStream IS = null;
        if (sources.equals("Directory")) {
            if (filename.contains("mp3")) {
                try {
                    startTime = System.currentTimeMillis();
                    IS = new MpegAudioFileReader().getAudioInputStream(soundFile);
                } catch (UnsupportedAudioFileException | IOException ex) {
                    Logger.getLogger(MusicPlayer.class.getName()).log(Level.SEVERE, null, ex);
                }
            } else if (filename.contains("m4a")) {
                try {
                    startTime = System.currentTimeMillis();
                    IS = new AACAudioFileReader().getAudioInputStream(soundFile);
                } catch (UnsupportedAudioFileException | IOException ex) {
                    Logger.getLogger(MusicPlayer.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        } else {
            String theURL = getPlayPreview(filename);
            try {
                startTime = System.currentTimeMillis();
                IS = new AACAudioFileReader().getAudioInputStream(new URL(theURL));
            } catch (UnsupportedAudioFileException | IOException ex) {
                Logger.getLogger(MusicPlayer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return IS;
    }

    public static void getDuration() {
        System.out.println("MusicPlayer.getDuration()");

        if (getMostCurrentLocation().equals("Directory")) {
            try {
                AudioFile audioFile = AudioFileIO.read(new File(filename));
                DurationTimer = audioFile.getAudioHeader().getTrackLength();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            DurationTimer = 30;
        }
        int Min = DurationTimer / 60;
        int Sec = DurationTimer % 60;
        String Secs;

        if (Sec < 10) {
            Secs = "0" + Sec;
        } else {
            Secs = "" + Sec;
        }
        EndDur = Min + ":" + Secs;
    }

    public static String getPlayPreview(String Path) {
        System.out.println("MusicPlayer.getPlayPreview(" + Path + ")");
        String previewRedirect = null;
        try {
            URLConnection con = new URL(Path).openConnection();
            //System.out.println("Orignal URL: " + con.getURL());
            con.connect();
            try (InputStream is = con.getInputStream()) {
                URL Redirect = con.getURL();
                previewRedirect = Redirect.toString();
                //System.out.println("Redirected URL: " + Redirect.toString());
                is.close();
            } catch (IOException ex) {
                Logger.getLogger(MusicPlayer.class.getName()).log(Level.SEVERE, null, ex);
            }
            PlayerUserInterface.setStatus("PLAYING");
        } catch (MalformedURLException ex) {
            Logger.getLogger(MusicPlayer.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(MusicPlayer.class.getName()).log(Level.SEVERE, null, ex);
        }
        return previewRedirect;
    }

    /**
     * @return the elapsed
     */
    public static float getElapsed() {
        return elapsed;
    }

    /**
     * @param aElapsed the elapsed to set
     */
    public static void setElapsed(float aElapsed) {
        elapsed = aElapsed;
    }

    /**
     * @param aPauseTime the PauseTime to set
     */
    public static void setPauseTime(long aPauseTime) {
        PauseTime = aPauseTime;
    }

    /**
     * @param aResumeTime the ResumeTime to set
     */
    public static void setResumeTime(long aResumeTime) {
        ResumeTime = aResumeTime;
    }

    /**
     * @param aTimeWaste the TimeWaste to set
     */
    public static void setTimeWaste(long aTimeWaste) {
        TimeWaste = aTimeWaste;
    }

    /**
     * @return the MostCurrentLocation
     */
    public static String getMostCurrentLocation() {
        return MostCurrentLocation;
    }

    /**
     * @param aMostCurrentLocation the MostCurrentLocation to set
     */
    public static void setMostCurrentLocation(String aMostCurrentLocation) {
        MostCurrentLocation = aMostCurrentLocation;
    }
}
